// Copyright 2019 Google, Inc.  All rights reserved.
// This code is governed by the BSD license found in the LICENSE file.
/*---
esid: prod-OptionalExpression
description: >
  optional chain on member expression
info: |
  Left-Hand-Side Expressions
    OptionalExpression:
      MemberExpression OptionalChain
features: [optional-chaining]
---*/

// PrimaryExpression
//   IdentifierReference
function Test() {
    const a = {b: 22};
    assert.sameValue(22, a?.b);
//   this
    function fn () {
      return this?.a
    }
    assert.sameValue(33, fn.call({a: 33}));
//   Literal
    assert.sameValue(undefined, "hello"?.a);
    assert.sameValue(undefined, null?.a);
//   ArrayLiteral
    assert.sameValue(2, [1, 2]?.[1]);
//   ObjectLiteral
    assert.sameValue(44, {a: 44}?.a);
//   FunctionExpression
    assert.sameValue('a', (function a () {}?.name));
//   ClassExpression
    assert.sameValue('Foo', (class Foo {}?.name));
//   GeneratorFunction
    assert.sameValue('a', (function * a () {}?.name));
//   AsyncFunctionExpression
    assert.sameValue('a', (async function a () {}?.name));
//   AsyncGeneratorExpression
    assert.sameValue('a', (async function * a () {}?.name));
//   RegularExpressionLiteral
    assert.sameValue(true, /[a-z]/?.test('a'));
//   TemplateLiteral
    assert.sameValue('h', `hello`?.[0]);
//   CoverParenthesizedExpressionAndArrowParameterList
    assert.sameValue(undefined, ({a: 33}, null)?.a);
    assert.sameValue(33, (undefined, {a: 33})?.a);

//  MemberExpression [ Expression ]
    const arr = [{a: 33}];
    assert.sameValue(33, arr[0]?.a);
    assert.sameValue(undefined, arr[1]?.a);

//  MemberExpression .IdentifierName
    const obj = {a: {b: 44}};
    assert.sameValue(44, obj.a?.b);
    assert.sameValue(undefined, obj.c?.b);

//  MemberExpression TemplateLiteral
    function f2 () {
      return {a: 33};
    }
    function f3 () {}
    assert.sameValue(33, f2`hello world`?.a);
    assert.sameValue(undefined, f3`hello world`?.a);

//  MemberExpression SuperProperty
    class A {
      a () {}
      undf () {
        return super.a?.c;
      }
    }
    class B extends A {
      dot () {
        return super.a?.name;
      }
      expr () {
        return super['a']?.name;
      }
      undf2 () {
        return super.b?.c;
      }
    }
    const subcls = new B();
    assert.sameValue('a', subcls.dot());
    assert.sameValue('a', subcls.expr());
    assert.sameValue(undefined, subcls.undf2());
    assert.sameValue(undefined, (new A()).undf());

// MemberExpression MetaProperty
    class C {
      constructor () {
        assert.sameValue(undefined, new.target?.a);
      }
    }
    new C();

// new MemberExpression Arguments
    class D {
      constructor (val) {
        this.a = val;
      }
    }
    assert.sameValue(99, new D(99)?.a);
}

// preheat
const NUMBER_OF_PREHEAT = 1;
for (let i = 0; i < NUMBER_OF_PREHEAT; i++) {
    Test();
}

ArkTools.jitCompileAsync(Test);
assert.sameValue(ArkTools.waitJitCompileFinish(Test), true, '[JIT] JIT disabled.');

// test
const NUMBER_OF_TEST = 1; // or 2
for (let i = 0; i < NUMBER_OF_PREHEAT; i++) {
    Test();
}
